package cn.demoncat.util.io;

import cn.demoncat.util.exception.IoRuntimeException;
import cn.demoncat.util.exception.ParamRuntimeException;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * 文件size工具：大小、空间
 * 
 * @author 延晓磊
 *
 * @since 2016年6月3日
 */
public class FileSizeUtil {

	private static final String EXP_FREE_SPACE = "获取磁盘可用空间失败：";
	private static final String EXP_FILE_SIZE = "获取文件尺寸失败：";
	
	
	/**
	 * 
	 * 根据大小适应bufSize
	 * 
	 * @return 默认1K，每1M增加10K，每10M增加100K，每100M增加1M，最大10M
	 */
	public static int autoSize(long size){
		//默认1024
		int bufSize = 1024;
		//大于1G，10M
		if (size > 1024) {
			bufSize = 1024*10240;
		}else if(size > 1){
			//每1M增加10K，每10M增加100K，每100M增加1M，最大10M
			bufSize = (int) (size * 10240);
		}
		return bufSize;
	}
	/**
	 * 
	 * 根据文件大小适应bufSize
	 * 
	 * @return 默认1K，每1M增加10K，每10M增加100K，每100M增加1M，最大10M
	 */
	public static int autoSize(File file){
		//获取文件大小(1M)
		long size = size(file)/1024/1024;
		//默认1024
		int bufSize = 1024;
		//大于1G，10M
		if (size > 1024) {
			bufSize = 1024*10240;
		}else if(size > 1){
			//每1M增加10K，每10M增加100K，每100M增加1M，最大10M
			bufSize = (int) (size * 10240);
		}
		return bufSize;
	}
	/**
	 * 
	 * 根据InputStream大小适应bufSize
	 * 
	 * @return 默认1K，每1M增加10K，每10M增加100K，每100M增加1M，最大10M
	 */
	public static int autoSize(InputStream in){
		//获取文件大小(1M)
		long size = size(in)/1024/1024;
		//默认1024
		int bufSize = 1024;
		//大于1G，10M
		if (size > 1024) {
			bufSize = 1024*10240;
		}else if(size > 1){
			//每1M增加10K，每10M增加100K，每100M增加1M，最大10M
			bufSize = (int) (size * 10240);
		}
		return bufSize;
	}
	
	/**
	 * 获取输入流可读取的字节数，即InputStream的大小
	 * 
	 * @param in
	 * @return 流为空或读取失败，返回-1
	 */
	public static long size(InputStream in){
		if (in == null) {
			return -1;
		}
		try {
			return in.available();
		} catch (IOException e) {
			return -1;
		}
	}
	
	/**
	 * 根据字节数，自动换算为文件尺寸的展示形式(EB、PB、TB、GB、MB、KB、bytes)
	 * 
	 * @param size
	 * @return 尺寸展示形式，如 1 bytes，976 KB
	 * @throws ParamRuntimeException 如果尺寸为null或小于0则抛出
	 */
	public static String sizeString(long size){
		if (size < 0) {
			throw ParamRuntimeException.ERROR;
		}
		return FileUtils.byteCountToDisplaySize(size);
	}
	
	/**
	 * 获取文件的尺寸(bytes)
	 * 
	 * @param file
	 * @return 文件为空或不存在则返回-1
	 * @throws IoRuntimeException 获取文件尺寸失败则抛出
	 */
	public static Long size(File file){
		if (file == null || ! file.exists()) {
			return -1L; 
		}
		try{
			return FileUtils.sizeOf(file);
		}catch(Exception e){
			throw new IoRuntimeException(EXP_FILE_SIZE + e.getMessage(), e);
		}
	}
	/**
	 * 获取指定文件所在磁盘的空闲空间(byte，总空间减去空闲空间即已用空间)
	 * 
	 * @return null表示根目录
	 * @throws IoRuntimeException 获取磁盘空间失败则抛出
	 */
	public static long spaceFree(File file){
		try {
			if (file == null) {
				long size = 0;
				//获取所有根目录磁盘的File
				File[] files = FileUtil.listRoot();
				for (File value : files) {
					//统计所有磁盘的可用空间
					size += value.getFreeSpace();
				}
				return size;
			}
			//获取文件所在磁盘的可用空间(bytes)
			return file.getFreeSpace();
		} catch (Exception e) {
			throw new IoRuntimeException(EXP_FREE_SPACE + e.getMessage(), e);
		}
	}
	/**
	 * 获取指定文件所在磁盘的总空间(byte)
	 * 
	 * @return null表示根目录
	 * @throws IoRuntimeException 获取磁盘空间失败则抛出
	 */
	public static long spaceTotal(File file){
		try {
			if (file == null) {
				long size = 0;
				//获取所有根目录磁盘的File
				File[] files = FileUtil.listRoot();
				for (File value : files) {
					//统计所有磁盘的总空间
					size += value.getTotalSpace();
				}
				return size;
			}
			//获取文件所在磁盘的总空间(bytes)
			return file.getTotalSpace();
		} catch (Exception e) {
			throw new IoRuntimeException(EXP_FREE_SPACE + e.getMessage(), e);
		}
	}
	/**
	 * 获取指定文件所在磁盘的可用空间(byte，空闲的空间有部分可能不可用)
	 * 
	 * @return null表示根目录
	 * @throws IoRuntimeException 获取磁盘空间失败则抛出
	 */
	public static long spaceUsable(File file){
		try {
			if (file == null) {
				long size = 0;
				//获取所有根目录磁盘的File
				File[] files = FileUtil.listRoot();
				for (File value : files) {
					//统计所有磁盘的总空间
					size += value.getUsableSpace();
				}
				return size;
			}
			//获取文件所在磁盘的可用空间(bytes)
			return file.getUsableSpace();
		} catch (Exception e) {
			throw new IoRuntimeException(EXP_FREE_SPACE + e.getMessage(), e);
		}
	}
}
